package com.example.databasedoc.controller;

import cn.smallbun.screw.core.Configuration;
import cn.smallbun.screw.core.engine.EngineConfig;
import cn.smallbun.screw.core.engine.EngineTemplateType;
import cn.smallbun.screw.core.execute.DocumentationExecute;
import cn.smallbun.screw.core.process.ProcessConfig;
import com.example.databasedoc.config.DataSourceFactory;
import com.example.databasedoc.config.DataSourceReq;
import com.example.databasedoc.config.MyHikariDataSource;
import com.example.databasedoc.enums.FileTypeEnum;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.FileCopyUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * DataBaseDocController
 *
 * @author lijunsong
 * @date 2021/3/15 14:30
 * @since 1.0
 */
@Slf4j
@RestController
@RequestMapping(value = "/databaseDoc")
public class DataBaseDocController {
    @Autowired
    DataSourceFactory factory;
    @Autowired
    ApplicationContext applicationContext;

    @SneakyThrows
    @PostMapping("/genDatabaseDoc")
    public ResponseEntity<byte[]> genDatabaseDoc(@Validated @RequestBody DataSourceReq req) {
        factory.reload(req.getUsername(), req.getPassword(), req.getUrl());
        MyHikariDataSource hikariCPDataSource = new MyHikariDataSource();
        DataSource dataSourceMysql = hikariCPDataSource.getDataSource();
        // 生成文件配置
        EngineConfig engineConfig = EngineConfig.builder()
                // 生成文件路径，自己本地的地址，这里需要自己更换下路径
                .fileOutputDir(req.getDir())
                // 打开目录
                .openOutputDir(false)
                // 文件类型
                .fileType(FileTypeEnum.fromKey(req.getFileType()).getValue())
                // 生成模板实现
                .produceType(EngineTemplateType.freemarker).build();
        // 生成文档配置（包含以下自定义版本号、描述等配置连接）
        Configuration config = Configuration.builder()
                .version("1.0.3")
                .description("生成文档信息描述")
                .dataSource(dataSourceMysql)
                .engineConfig(engineConfig)
                .produceConfig(getProcessConfig())
                .build();
        // 执行生成
        new DocumentationExecute(config).execute();

        File files = new File(req.getDir());
        
        return downloadFile(new File(String.format("%s/%s", req.getDir(), files.list()[0])));
    }

    private ResponseEntity<byte[]> downloadFile(File file) throws IOException {
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentDispositionFormData("attachment", URLEncoder.encode(file.getName(), "utf-8"));
            return new ResponseEntity<>(FileCopyUtils.copyToByteArray(file), headers, HttpStatus.OK);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw e;
        } finally {
            if (file != null) {
                log.info("delete file {}.", file.getName());
                Files.delete(file.toPath());
            }
        }
    }

    /**
     * 配置想要生成的表+ 配置想要忽略的表
     *
     * @return 生成表配置
     */
    private static ProcessConfig getProcessConfig() {
        // 忽略表名
        List<String> ignoreTableName = Arrays.asList("a", "test_group");
        // 忽略表前缀，如忽略a开头的数据库表
        List<String> ignorePrefix = Arrays.asList("a", "t");
        // 忽略表后缀
        List<String> ignoreSuffix = Arrays.asList("_test", "czb_");
        return ProcessConfig.builder()
                //根据名称指定表生成
                .designatedTableName(new ArrayList<>())
                //根据表前缀生成
                .designatedTablePrefix(new ArrayList<>())
                //根据表后缀生成
                .designatedTableSuffix(new ArrayList<>())
                //忽略表名
                .ignoreTableName(ignoreTableName)
                //忽略表前缀
                .ignoreTablePrefix(ignorePrefix)
                //忽略表后缀
                .ignoreTableSuffix(ignoreSuffix).build();
    }
}
